package com.ouyunc.oauth2.base;


import com.ouyunc.common.constant.enums.UserDetailEnum;
import com.ouyunc.common.base.UserDetail;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldNameConstants;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author fangzhenxun
 * @Description 登录用户的基础信息,其他用户可以继承该类封装成该信息
 * @Date 2020/4/25 14:14
 **/
@Data
@FieldNameConstants
@AllArgsConstructor
@NoArgsConstructor
public class BaseUser<T> implements UserDetails, Serializable {

    private static final long serialVersionUID = -6676367456949935406L;
    /**
     * 用户名称
     **/
    @ApiModelProperty("用户名称")
    private String username;

    /**
     * 密码
     **/
    @ApiModelProperty("密码")
    private String password;

    /**
     * 用户实体类的信息，需要在实体类中的某个字段上添加注解 @UserDetail 标识对应的userDetail 中的字段
     **/
    @ApiModelProperty("用户的信息")
    private T userDetail;

    /**
     * 是否开启 0-未启用，1-启用
     **/
    @ApiModelProperty("是否开启 0-未启用，1-启用")
    private boolean enabled = true;

    /**
     * 账户是否过期 0-过期，1-未过期
     **/
    @ApiModelProperty("账户是否过期 0-过期，1-未过期")
    private boolean accountNonExpired = true;

    /**
     * 账户是否锁定 0-锁定，1-未锁定
     **/
    @ApiModelProperty("账户是否锁定 0-锁定，1-未锁定")
    private boolean accountNonLocked = true;

    /**
     * 凭据是否过期 0-过期，1-未过期
     **/
    @ApiModelProperty("凭据是否过期 0-过期，1-未过期")
    private boolean credentialsNonExpired = true;


    /**
     * 用户所有权限集合, 在Security中，角色和权限共用GrantedAuthority接口，唯一的不同角色就是多了个前缀"ROLE_"
     **/
    private Set<GrantedAuthority> authorities = new HashSet<>();


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }


    /**
     * @Author fangzhenxun
     * @Description  设置用户详情
     * @Date 2020/7/3 14:33
     * @param userDetail
     * @return void
     **/
    public void setUserDetail(T userDetail) {
        this.userDetail = userDetail;
        Class<?> userDetailClass = userDetail.getClass();
        //获取该实体类中的特有注解，取出该注解所对应的属性上的值给该baseUser特定字段进行赋值
        Field[] fields = userDetailClass.getDeclaredFields();
        for (Field field : fields) {
            //假设不为空。设置可见性，然后返回
            field.setAccessible(true);
            UserDetail annotation = field.getAnnotation(UserDetail.class);
            if (annotation != null) {
                UserDetailEnum userDetailEnum = annotation.fieldName();

                //获取 当前对象的字段值,并且给其它userDetail赋值
                Object fieldValue = null;
                try {
                    fieldValue = field.get(userDetail);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                //给用户名赋值
                if (UserDetailEnum.USERNAME.getFieldName().equals(userDetailEnum.getFieldName())) {
                    this.username = (String) fieldValue;
                }
                //给密码赋值
                if (UserDetailEnum.PASSWORD.getFieldName().equals(userDetailEnum.getFieldName())) {
                    this.password = (String) fieldValue;
                    // 将该密码重置空
                    try {
                        field.set(userDetail, null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
                //给权限赋值，注意如果是角色需要在数据库中查出来的时候就加上 ROLE_ + xxx
                if (UserDetailEnum.AUTHORITIES.getFieldName().equals(userDetailEnum.getFieldName())) {
                    Set<String> userAuthorities = (Set<String>) fieldValue;
                    if (!CollectionUtils.isEmpty(userAuthorities)) {
                        this.authorities = userAuthorities.parallelStream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
                    }

                }
            }
        }
    }
}
